package com.hll.spring_book.aop;

import com.hll.spring_book.annotion.logAnno;
import com.hll.spring_book.pojo.Log;
import com.hll.spring_book.pojo.User;
import com.hll.spring_book.service.log.LogService;
import com.hll.spring_book.util.AnnotationResolver;
import com.hll.spring_book.util.SessionHelper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
public class LogAspect {
  /*保存日志到数据库中*/
  /* private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);*/
  @Resource private LogService logService;
  private User user;
  private HttpServletRequest request;

  @Pointcut(
      "execution(public * com.hll.spring_book.controller..*.*(..))") // 切入点描述 这个是controller包的切入点
  public void controllerLog() {} // 签名，可以理解成这个切入点的一个名称

  @After("controllerLog()") // 在切入点的方法run后要干的
  public void logAfterController(JoinPoint joinPoint) {

    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    logAnno annotation = signature.getMethod().getAnnotation(logAnno.class);
    /*只有携带该注解才需要日志存储*/
    if (annotation != null && user != null) {
      // 通过AnnotationResolve解析注解属性参数
      AnnotationResolver annotationResolver = AnnotationResolver.newInstance();
      Object paramObj = annotationResolver.resolver(joinPoint, annotation.value());
      Object description = annotationResolver.resolver(joinPoint, annotation.description());
      // 下面这个getSignature().getDeclaringTypeName()是获取包+类名的
      // 然后后面的joinPoint.getSignature.getName()获取了方法名
      Log log =
          new Log(
              null,
              user.getId(),
              description.toString(),
              joinPoint.getSignature().getDeclaringTypeName()
                  + "."
                  + joinPoint.getSignature().getName(),
              Arrays.toString(joinPoint.getArgs()),
              request.getRequestURL().toString(),
              request.getRemoteAddr(),
              new Date());
      logService.insert(log);
      // logger.info("################TARGET: " + joinPoint.getTarget());//返回的是需要加强的目标类的对象
      // logger.info("################THIS: " + joinPoint.getThis());//返回的是经过加强后的代理类的对象
    }
  }

  /*因为after后无法获取request，所以先保存*/
  @Before("controllerLog()") // 在切入点的方法run前要干的
  public void doBefore(JoinPoint joinPoint) throws Throwable {
    RequestAttributes requestAttributes =
        RequestContextHolder.getRequestAttributes(); // 这个RequestContextHolder是Springmvc提供来获得请求的东西
    this.request = ((ServletRequestAttributes) requestAttributes).getRequest();
    this.user = SessionHelper.getUser();
  }
}
